/*
 * PDLogger
 * 
 * Copyright (c) 2012, Zoujie Wu <yibn2008@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 
 *   * Redistributions of source code must retain the above copyright notice, this 
 *     list of conditions and the following disclaimer.
 *   
 *   * Redistributions in binary form must reproduce the above copyright notice, 
 *     this list of conditions and the following disclaimer in the documentation 
 *     and/or other materials provided with the distribution.
 *   
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/* $Id$ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef PHP_WIN32
#include "win32/time.h"
#else
#include <sys/time.h>
#endif

#include "php.h"
#include "php_pdlogger.h"
#include "pdl_record.h"

#define LOG_RETURN_IF_NOT_STARTED \
	do { \
		if (!PDL_G(enable) || !PDL_G(started)) { \
			return; \
		} \
	} while(0)

/**
 * Record log and store it in global records
 * @return the inserted record id
 */
PDL_API ulong pdl_record(int level, char *label, uint label_len, char *msg, uint msg_len, const char *call_file, uint line, zval *data TSRMLS_DC)
{
	pdl_record_t	*record;
	char			*file;
	ulong			id = -1;
	HashTable		*ht = &PDL_G(records);

	if (ht) {
		record = (pdl_record_t *) emalloc(sizeof(pdl_record_t));

		if (data) {
			Z_ADDREF_P(data);
		}

		if (!call_file) {
			if (zend_is_executing(TSRMLS_C)) {
				file = estrdup(zend_get_executed_filename(TSRMLS_C));
				line = zend_get_executed_lineno(TSRMLS_C);
			} else {
				file = estrndup(PDL_FILE_UNKNOWN, sizeof(PDL_FILE_UNKNOWN)-1);
				line = 0;
			}
		} else {
			file = estrdup(call_file);
		}

		record->level 		= level;
		record->time		= pdl_get_curr_time();
		record->label 		= estrndup(label, label_len);
		record->msg			= estrndup(msg, msg_len);
		record->data 		= data;
		record->file 		= file;
		record->line 		= line;

		/* insert a new record */
		id = zend_hash_next_free_element(ht);
		zend_hash_index_update(ht, id, &record, sizeof(pdl_record_t *), NULL);
	}

	return id;
}

/* {{{ proto void pdl_info(string $label, string $msg[, mixed $data])
 */
PHP_FUNCTION(pdl_info)
{
	char	*label;
	uint	label_len;
	char	*msg;
	uint	msg_len;
	zval	*data = NULL;

	LOG_RETURN_IF_NOT_STARTED;

	if (PDL_G(started)) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|z!", &label, &label_len, &msg, &msg_len, &data) == FAILURE) {
			return;
		}

		pdl_record(PDL_LV_INFO, label, label_len, msg, msg_len, NULL, 0, data TSRMLS_CC);
	}
}
/* }}} */

/* {{{ proto void pdl_warning(string $label,string $msg[, mixed $data])
 */
PHP_FUNCTION(pdl_warning)
{
	char	*label;
	uint	label_len;
	char	*msg;
	uint	msg_len;
	zval	*data = NULL;
	
	LOG_RETURN_IF_NOT_STARTED;
	
	if (PDL_G(started)) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|z!", &label, &label_len, &msg, &msg_len, &data) == FAILURE) {
			return;
		}

		pdl_record(PDL_LV_WARNING, label, label_len, msg, msg_len, NULL, 0, data TSRMLS_CC);
	}
}
/* }}} */

/* {{{ proto void pdl_error(string $label,string $msg[, mixed $data])
 */
PHP_FUNCTION(pdl_error)
{
	char	*label;
	uint	label_len;
	char	*msg;
	uint	msg_len;
	zval	*data = NULL;
	
	LOG_RETURN_IF_NOT_STARTED;
	
	if (PDL_G(started)) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|z!", &label, &label_len, &msg, &msg_len, &data) == FAILURE) {
			return;
		}
		
		pdl_record(PDL_LV_ERROR, label, label_len, msg, msg_len, NULL, 0, data TSRMLS_CC);
	}
}
/* }}} */

/* {{{ proto void pdl_exception(string $label, Exception $data)
 */
PHP_FUNCTION(pdl_exception)
{
	char *label;
	uint label_len;
	zval *data;
	
	LOG_RETURN_IF_NOT_STARTED;

	if (PDL_G(started)) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &label, &label_len, &data) == FAILURE) {
			return;
		}
		
		pdl_record(PDL_LV_EXCEPTION, label, label_len, ZEND_STRL(PDL_MSG_EXCEPTION), NULL, 0, data TSRMLS_CC);
	}
}
/* }}} */

/* {{{ proto void pdl_dump(mixed $data)
 */
PHP_FUNCTION(pdl_dump)
{
	zval *data;

	LOG_RETURN_IF_NOT_STARTED;

	if (PDL_G(started)) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &data) == FAILURE) {
			return;
		}

		pdl_record(PDL_LV_DEBUG, ZEND_STRL(PDL_LABEL_DUMP), ZEND_STRL(PDL_MSG_DUMP), NULL, 0, data TSRMLS_CC);
	}
}
/* }}} */

/* {{{ proto long pdl_records_num()
 */
PHP_FUNCTION(pdl_records_num)
{
	RETURN_LONG((long) zend_hash_num_elements(&PDL_G(records)));
}
/* }}} */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */
